using System;
using System.Collections;
using System.Linq;
using UnityEngine;

public class Player : MonoBehaviour
{
    public static Player Instance;
    public PlayerInput PlayerInput { get; private set; }
    public Vector2 MoveInput { get; private set; }
    public Animator PlayerAnimator { get; private set; }
    public Rigidbody2D Rb { get; private set; }
    public Collider2D Coll { get; private set; }
    public StateMachine StateMachine { get; private set; }
    public ViewType CurrentViewType;
    private SpriteRenderer _spriteRenderer;
    public UI UI { get; private set; }

    [Header("-----Side Detail -----")]  
    public float _sidemoveSpeed = 5f;

    [Header("-----Top Detail -----")]
    [SerializeField] private LayerMask whatIsGround;
    [SerializeField] private float checkDistance;
    public float topGravityScale = 4f;
    public float _topmoveSpeed = 7f;
    public float _topJumpForce = 7f;


    public float FacingDir { get; private set; } = 1;

    #region Player State
    public PlayerState_SideIdle PlayerSideIdleState { get; private set; }
    public PlayerState_SideMove PlayerSideMoveState { get; private set; }
    public PlayerState_TopIdle PlayerTopIdleState { get; private set; }
    public PlayerState_TopMove PlayerTopMoveState { get; private set; }
    public PlayerState_TopJump PlayerTopJumpState { get; private set; }
    public PlayerState_TopAttack PlayerTopAttackState { get; private set; }
    public PlayerState_TopFall PlayerTopFallState { get; private set; }
    #endregion
    private void Awake()
    {
        Instance = this;
        _spriteRenderer = GetComponentInChildren<SpriteRenderer>();
        PlayerAnimator = GetComponentInChildren<Animator>();
        Rb = GetComponent<Rigidbody2D>();
        Coll = GetComponent<Collider2D>();
        UI = FindObjectOfType<UI>();
        StateMachine = new();
        PlayerInput = new();
        UI.SetUI(PlayerInput);
        PlayerSideIdleState = new(StateMachine, this, "Side_Idle");
        PlayerSideMoveState = new(StateMachine, this, "Side_Move");

        PlayerTopIdleState = new(StateMachine, this, "Top_Idle");
        PlayerTopMoveState = new(StateMachine, this, "Top_Move");
        PlayerTopJumpState = new(StateMachine, this, "Top_Jump");
        PlayerTopAttackState = new(StateMachine, this, "Top_Attack");
        PlayerTopFallState = new(StateMachine, this, "Top_Fall");
    }
    private void OnEnable()
    {
        PlayerInput.Player.Move.performed += context => MoveInput = context.ReadValue<Vector2>();
        PlayerInput.Player.Move.canceled += context => MoveInput = Vector2.zero;
        PlayerInput.Player.Interact.performed += context => TryInteract();

        EventCenter.AddEventListener<ViewType>(EventName.SwitchViewState, SwitchViewState);
        EventCenter.AddEventListener(EventName.PlayerDead, HandlePlayerDead);
    }
    private void OnDisable()
    {
        PlayerInput.Player.Move.performed -= context => MoveInput = context.ReadValue<Vector2>();
        PlayerInput.Player.Move.canceled -= context => MoveInput = Vector2.zero;
        PlayerInput.Player.Interact.performed -= context => TryInteract();

        EventCenter.RemoveEventListener<ViewType>(EventName.SwitchViewState, SwitchViewState);
        EventCenter.RemoveEventListener(EventName.PlayerDead, HandlePlayerDead);
    }

    private void Start()
    {
        PlayerInput.Player.Enable();
        SwitchViewState(CurrentViewType);
    }
    private void Update()
    {
        StateMachine.Update();
    }
    private void FixedUpdate()
    {
        StateMachine.FixedUpdate();
    }

    public void SetVelocityZero() => Rb.velocity = new(0, 0);

    public void SetVelocity(float xVelocity, float yVelcotiy)
    {
        Rb.velocity = new(xVelocity, yVelcotiy);

        UpdateFlip(xVelocity);
    }

    public void UpdateFlip(float direction)
    {
        if (NeedToFlip(direction))
            HandleFlip();
    }
    public bool NeedToFlip(float direction) => direction > 0 && FacingDir == -1 || direction < 0 && FacingDir == 1;
    public virtual void HandleFlip()
    {
        _spriteRenderer.transform.Rotate(0, 180f, 0);
        FacingDir = -FacingDir;

        //翻转时触发相机跟随的目标对象翻转
        EventCenter.TriggerEvent(EventName.Camera_FollowTarget);
    }

    public bool IsGround() => Physics2D.Raycast(transform.position, Vector2.down, checkDistance, whatIsGround);
    public void SwitchViewState(ViewType viewType)
    {
        if (viewType == ViewType.Side)
        {
            Debug.Log("转换为平面视角");
            StateMachine.SwitchState(PlayerSideIdleState);
        }
        else if (viewType == ViewType.Top)
        {
            Debug.Log("转换为横板视角");
            Rb.gravityScale = topGravityScale;
            StateMachine.SwitchState(PlayerTopIdleState);
        }
        CurrentViewType = viewType;
    }

    //尝试交互
    private void TryInteract()
    {
        Collider2D[] objectAround = Physics2D.OverlapCircleAll(transform.position, 1f);

        if (objectAround.Length == 0)
        {
            Debug.Log("没有找到可交互目标");
            return;
        }
        //筛选
        IInteractive closestInteract = objectAround
                ?.Where(t => t.GetComponent<IInteractive>() != null)
                ?.OrderBy(t => Vector2.Distance(transform.position, t.transform.position))
                ?.Select(t => t.GetComponent<IInteractive>())
                ?.FirstOrDefault();

        closestInteract?.Interact();
    }
    private void HandlePlayerDead()
    {
        PlayerInput.Disable();

        StartCoroutine(ReLoadSceneCo());
    }
    private IEnumerator ReLoadSceneCo()
    {
        yield return new WaitForSeconds(1f);

        LoadSceneManager.Instance.LoadScene("Game");
    }
    private void OnDrawGizmos()
    {
        Gizmos.color = Color.green;

        Gizmos.DrawLine(transform.position, transform.position + Vector3.down * checkDistance);
    }
}
